package org.jivesoftware.spark.crowd.packet;

import java.awt.Color;
import java.awt.Image;
import java.awt.SystemTray;
import java.awt.TrayIcon;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import java.util.Vector;

import javax.swing.Icon;
import javax.swing.SwingUtilities;

import org.jivesoftware.resource.Default;
import org.jivesoftware.resource.SparkRes;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.PacketExtension;
import org.jivesoftware.smack.packet.Presence;
import org.jivesoftware.smack.util.StringUtils;
import org.jivesoftware.spark.ChatManager;
import org.jivesoftware.spark.PluginManager;
import org.jivesoftware.spark.PresenceManager;
import org.jivesoftware.spark.SparkManager;
import org.jivesoftware.spark.crowd.CrowdRecorder;
import org.jivesoftware.spark.crowd.CrowdsManager;
import org.jivesoftware.spark.crowd.Param;
import org.jivesoftware.spark.crowd.impl.Crowd;
import org.jivesoftware.spark.crowd.impl.Member;
import org.jivesoftware.spark.crowd.packet.CrowdsMessageManager.CrowdMessageProcesser;
import org.jivesoftware.spark.crowd.ui.CrowdChatRoom;
import org.jivesoftware.spark.crowd.ui.MemberListPane;
import org.jivesoftware.spark.crowd.ui.UIEventManager;
import org.jivesoftware.spark.ui.ChatRoom;
import org.jivesoftware.spark.ui.ChatRoomNotFoundException;

public class ReceivedPacketProcesser {
	private static ReceivedPacketProcesser instance;

	private Map<String, CrowdsPresenceManager.PresenceUpdater> presenceUpdaters = new HashMap<String, CrowdsPresenceManager.PresenceUpdater>();

	private CrowdsMessageManager messageManager;

	private CrowdsPresenceManager presenceManager;
	private CrowdsManager crowdsManager;

	private CrowdsIQManager iqManager;

	private Vector<Message> localDelayMessages = new Vector<Message>();

	public static ReceivedPacketProcesser getInstance() {
		if (instance == null)
			instance = new ReceivedPacketProcesser();
		return instance;
	}

	private ReceivedPacketProcesser() {

	}

	
	public Vector<Message> getLocalDelayMessages() {
		return localDelayMessages;
	}

	/**
	 * This listener is relatively persistent . It exists in the hole client
	 * running period.
	 */
	public void initMessageListener() {

		messageManager.addMessageListener(new CrowdMessageProcesser() {
			
			@Override
			public void receiveMessage(final Message m) {
				
				String messageNode = StringUtils.parseName(m.getFrom());
				String resource = StringUtils.parseResource(m.getFrom());
				String domain = StringUtils.parseServer(m.getFrom());

				String crowdName = "";
				String memberJID = "";
				PacketExtension ext = m.getExtension(Param.CROWD_SERVICE_NAME,
						Param.message_NS);
				if (ext instanceof MParser) {
					MParser mp = (MParser) ext;
					crowdName = mp.getCrowdName();
					memberJID = mp.getMemberJID();
				}

				/*
				 * if(messageNode.equals("")){ String nickName = null;
				 * if(resource.equals("")) nickName = "服务器"; else nickName =
				 * resource; broadcastMessage(m,nickName); return; }
				 */

				try {
					ChatRoom room = (CrowdChatRoom) (Param.getChatContainer()
							.getChatRoom(crowdName));
					String nickname = CrowdsManager.getInstance()
							.findCrowdByName(crowdName).findMemberByJID(
									memberJID).getNickName();
					if (nickname == null)
						nickname = SparkManager.getUserManager().getNickname(
								memberJID);
					// TODO have not considered super link like URL ,http://
					// and image icons

					room.getTranscriptWindow().insertMessage(nickname, m,
							ChatManager.FROM_COLOR, new Color(0, 0, 0, 0));
					

				} catch (ChatRoomNotFoundException e) {					
						localDelayMessages.add(m);
						/*for(Message mes : localDelayMessages){
							System.out.println(mes.getBody());
						}*/
				}

			}
		});

		new Thread(new Runnable() {

			public void run() {
				
				while (true) {
					final Timer timer = new Timer();
					if (!localDelayMessages.isEmpty()) {
						final Message m = localDelayMessages.get(0);
						
						for (final TrayIcon ti : SystemTray.getSystemTray().getTrayIcons()) {
							if (ti.getToolTip().equals(Default.getString(Default.APPLICATION_NAME))) {
								final Image img = ti.getImage();
								ti.setToolTip("有新的群消息");
								timer.schedule(new TimerTask() {
									@Override
									public void run() {
										if (ti.getImage() == img)
											ti.setImage(Param.getCrowdIcon()
													.getImage());
										else
											ti.setImage(img);
									}
								}, 0, 500);
								ti.addMouseListener(new MouseAdapter() {
									@Override
									public void mouseClicked(MouseEvent e) {
										if (e.getClickCount() == 2) {
											PacketExtension ext = m.getExtension(
													Param.CROWD_SERVICE_NAME, Param.message_NS);
											String crowdName = null;
											if (ext instanceof MParser) {												
												crowdName = ((MParser) ext).getCrowdName();												
											}
											UIEventManager.getInstance().openRoom(crowdName);
											
											ti.removeMouseListener(this);
											timer.cancel();
											timer.purge();
											ti.setImage(img);
											ti.setToolTip(Default.getString(Default.APPLICATION_NAME));
										}
									}
								});
								
								synchronized (localDelayMessages) {
									try {
										localDelayMessages.wait();
//										ti.removeMouseListener(this);
										ti.removeMouseListener(ti.getMouseListeners()[ti.getMouseListeners().length-1]);
										timer.cancel();
										timer.purge();
										ti.setImage(img);
										ti.setToolTip(Default.getString(Default.APPLICATION_NAME));
									} catch (InterruptedException e1) {										
										e1.printStackTrace();
									}
								}

							}
						}
					}
					try {
						Thread.sleep(5000);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
			}

		}).start();

	}

	/**
	 * 
	 * @param roomName
	 * @param members
	 */
	private void showMembers(String roomName, List<Member> members) {
		try {
			CrowdChatRoom room = (CrowdChatRoom) Param.getChatContainer()
					.getChatRoom(roomName);

			MemberListPane memberListPane = room.getMemberListPane();
			Collections.sort(members, memberComp);
			for (int i = 0; i < members.size(); i++) {
				Member m = members.get(i);
				Icon icon = null;
				if (m.getPresence() != null)
					icon = PresenceManager.getIconFromPresence(m.getPresence());
				else
					icon = SparkRes.getImageIcon(Param.getUnavailableIcon());
				String nickname = m.getNickName();

				memberListPane.addMember(icon, nickname, i);

			}
		} catch (ChatRoomNotFoundException e) {
			CrowdRecorder
					.record("CrowdUIManager showMembers error : ChatRoomNotFoundException --"
							+ roomName);
		} catch (ClassCastException cce) {
			cce.printStackTrace();
			CrowdRecorder
					.record("CrowdsManager receiveMembersInACrowd ClassCastException");
		}

	}
	/**
	 * 
	 * @param crowdName
	 * @param members
	 */
	public void receiveMembersInACrowd(final String crowdName,
			final List<Member> members) {
		Crowd crowd = crowdsManager.findCrowdByName(crowdName);
		if (crowd != null) {
			crowd.receiveMembersInACrowd(members);
			crowd.setMembersLoaded(true);
		} else {
			CrowdRecorder
					.record("CrowdsManager receiveMembersInACrowd error : can't find the crowd \""
							+ crowdName + "\"");
		}
		try {
			SwingUtilities.invokeAndWait(new Runnable() {
				@Override
				public void run() {
					showMembers(crowdName, members);
				}
			});
		} catch (InterruptedException e) {
			CrowdRecorder
					.record("ReceivedPacketProcesser - receiveMembersInACrowd - loadMembers : InterruptedException");
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			CrowdRecorder
					.record("ReceivedPacketProcesser - receiveMembersInACrowd - loadMembers : InvocationTargetException");
			e.printStackTrace();
		}

	}
	/**
	 * 
	 * @param roomName
	 */
	public void addCrowdPresenceListener(final String roomName) {
		try {
			CrowdsPresenceManager.PresenceUpdater presenceUpdater = new CrowdsPresenceManager.PresenceUpdater() {
				final CrowdChatRoom room = (CrowdChatRoom) Param
						.getChatContainer().getChatRoom(roomName);

				@Override
				public void crowdPresenceChanged(Presence newPresence) {

					String fromBareJID = StringUtils
							.parseBareAddress(newPresence.getFrom());

					Crowd crowd = CrowdsManager.getInstance().findCrowdByName(
							roomName);

					Member member = crowd.findMemberByJID(fromBareJID);
					if (member == null)
						return;
					Presence oldPresence = member.getPresence();
					if (oldPresence == null)
						oldPresence = PresenceManager.getPresence(member
								.getJID());
					member.setPresence(newPresence);

					String nickname = member.getNickName();
					Icon userIcon = PresenceManager
							.getIconFromPresence(newPresence);
					if (oldPresence.getType() == Presence.Type.unavailable
							&& newPresence.getType() == Presence.Type.available)
						room.getMemberListPane()
								.moveToFirst(userIcon, nickname);
					else if (oldPresence.getType() == Presence.Type.available
							&& newPresence.getType() == Presence.Type.unavailable)
						room.getMemberListPane().moveToLast(userIcon, nickname);
					else {
						room.getMemberListPane().updateIcon(userIcon, nickname);
					}

				}

			};

			presenceManager.addCrowdPresenceUpdater(presenceUpdater);
			presenceUpdaters.put(roomName, presenceUpdater);
		} catch (Exception e) {
			e.printStackTrace();
			CrowdRecorder
					.record("CrowdUIManager addCrowdPresenceListener error : ChatRoomNotFoundException --"
							+ roomName);
		}

	}
	/**
	 * 
	 * @param roomName
	 * @return
	 */
	public CrowdsPresenceManager.PresenceUpdater removeCrowdPresenceListener(
			String roomName) {
		if (presenceUpdaters.containsKey(roomName))
			return this.presenceUpdaters.remove(roomName);
		return null;
	}
	/**
	 * 
	 */
	public void init() {
		this.crowdsManager = CrowdsManager.getInstance();
		this.messageManager = CrowdsMessageManager.getInstance(Param
				.getConnection(), Param.CROWD_SERVICE_NAME);
		this.presenceManager = CrowdsPresenceManager.getInstance(Param
				.getConnection(), Param.CROWD_SERVICE_NAME);
		this.iqManager = CrowdsIQManager.getInstance(Param.getConnection(),
				Param.CROWD_SERVICE_NAME);
		this.initMessageListener();
	}
	/**
	 * 
	 * @param localCrowds
	 */
	public void receiveCrowdsLocal(ArrayList<Crowd> localCrowds) {
		crowdsManager.receiveCrowdsLocal(localCrowds);
	}

	private void broadcastMessage(Message m, String nickName) {
		// TODO
	}
	/**
	 * 
	 */
	final Comparator<Member> memberComp = new Comparator<Member>() {

		@Override
		public int compare(Member o1, Member o2) {
			if (o1.getJID().equals(Param.getBareAddress()))
				return 1;
			if (o2.getJID().equals(Param.getBareAddress()))
				return -1;
			int result = 0;
			String jid1 = o1.getJID();
			String jid2 = o2.getJID();

			Presence p1 = o1.getPresence() == null ? PresenceManager
					.getPresence(jid1) : o1.getPresence();
			Presence p2 = o2.getPresence() == null ? PresenceManager
					.getPresence(jid2) : o2.getPresence();
			if (p1 == null || p1 == null || (p1.getType() == p2.getType())) {
				result = jid1.compareTo(jid2);
			} else {
				result = p1.getType() == Presence.Type.available ? 1 : 0;
			}
			return result;
		}
	};
}